home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_075 / hardcopy / hardcopy.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  15KB  |  565 lines

  1. /*
  2.  *  HARCOPY.C    copy CLI output to file as well as window.
  3.  *
  4.  *  By Davide P. Cervone, Copywrite (c) 1987
  5.  *
  6.  *  Based heavily on a source by Phillip Lindsay, (c) 1987 Commodore-Amiga, Inc.
  7.  *  You may use this source as long as this copywrite notice is left intact.
  8.  */
  9.  
  10. #include <exec/types.h>
  11. #include <exec/ports.h>
  12. #include <exec/semaphores.h>
  13. #include <libraries/dos.h>
  14. #include <libraries/dosextens.h>
  15. #include <stdio.h>
  16.  
  17. #ifdef MANX
  18. #include <functions.h>
  19. #endif
  20.  
  21. /*
  22.  *  AmigaDOS uses task signal bit 8 for message signaling
  23.  */
  24.  
  25. #define ONE          1L
  26. #define DOS_SIGNAL   8
  27. #define DOS_MASK     (ONE<<DOS_SIGNAL)
  28.  
  29.  
  30. /*
  31.  *  Cast a pointer to become a structure pointer
  32.  */
  33.  
  34. #define PTR(x,p)     ((struct x *)(p))
  35.  
  36.  
  37. /*
  38.  *  AmigaDOS packet types we're interested in viewing
  39.  */
  40.  
  41. #define _ACTION_READ              82L
  42. #define _ACTION_WRITE             87L
  43.  
  44.  
  45. /*
  46.  *  Short-hand for the parts of the DosPacket
  47.  */
  48.  
  49. #define ARG1    pkt->dp_Arg1
  50. #define ARG2    pkt->dp_Arg2
  51. #define RES1    pkt->dp_Res1
  52.  
  53.  
  54. /*
  55.  *  Program functions
  56.  */
  57.  
  58. #define SHOW_USAGE       0
  59. #define START_HARDCOPY   1
  60. #define DO_MONITOR       2
  61. #define END_HARDCOPY     3
  62.  
  63.  
  64. /*
  65.  *  External routines and variables
  66.  */
  67.  
  68. extern LONG AllocSignal(), Wait();
  69. extern struct FileHandle *Open();
  70. extern struct Message *PacketWait(), *GetMsg();
  71. extern struct Process *FindTask();
  72. extern struct DosLibrary *DOSBase;
  73. extern void GetDateTime();
  74.  
  75.  
  76. /*
  77.  *  Our own variables
  78.  */
  79.  
  80. static char *version   = "HARDCOPY v1.0, 4/25/87";
  81. static char *copywrite = "Copywrite (c) 1987 by Davide P. Cervone";
  82.  
  83. struct MsgPort         *thePort;        /* the port we will be monitoring */
  84. struct Process         *myProcess;      /* pointer to our own process */
  85. struct Process         *ChosenProcess;  /* the process we are monitoring */
  86. ULONG                  WaitMask;        /* the task signal mask */
  87. struct SignalSemaphore CanReturn = {0}; /* coordinates PacketWait */
  88. struct Message         *theMessage;     /* the message we received */
  89. APTR                   OldPktWait;      /* the old pr_PktWait routine */
  90. APTR                   OldUserData;     /* tc_UserData for monitored task */
  91.  
  92.  
  93. #ifdef MANX
  94.    LONG PWait();        /* this is the ASM stub that calls PacketWait() */
  95. #else
  96.    #define PWait   PacketWait
  97. #endif
  98.  
  99. #ifndef MANX
  100.    Ctrl_C()             /* Control-C Trap routine for Lattice */
  101.    {
  102.       return(0);
  103.    }
  104. #endif
  105.  
  106.  
  107. /*
  108.  *  PacketWait()
  109.  *
  110.  *  This is the routine placed in the pr_PktWait field of the monitored
  111.  *  precess.  It is run asynchronously by the monitored process, and is
  112.  *  called whenever AmigaDOS does a taskwait().  PacketWait() waits for
  113.  *  a message to come in and then signals the monitoring task that one has
  114.  *  arrived.  It then attempts to obtain the semaphore, which will not be
  115.  *  released by the monitoring process until it is finished printing the 
  116.  *  contents of the packet.
  117.  */
  118.  
  119. struct Message *PacketWait()
  120. {
  121. #ifdef MANX
  122.    /*
  123.     *  if MANX, make sure we can see our data
  124.     */
  125.    geta4();
  126. #endif
  127.  
  128.    SetSignal(FALSE,DOS_MASK);
  129.  
  130.    while(!(theMessage = GetMsg(thePort)))  Wait(DOS_MASK);
  131.  
  132.    Signal(myProcess,WaitMask);
  133.    ObtainSemaphore(&CanReturn);
  134.    ReleaseSemaphore(&CanReturn);
  135.  
  136.    return(theMessage);
  137.  
  138.  
  139. /*
  140.  *  printBUF()
  141.  *
  142.  *  Prints a buffer to stdout.
  143.  */
  144.  
  145. void printBUF(buf,len)
  146. char *buf;
  147. int len;
  148. {
  149.    short i;
  150.    char outbuf[81];
  151.  
  152.    while (len > 0)
  153.    {
  154.       for (i=0; i<80 && len>0; i++,len--) outbuf[i] = *buf++;
  155.       outbuf[i] = '\0';
  156.       printf("%s",outbuf);
  157.    }
  158. }
  159.  
  160.  
  161. /*
  162.  *  PrintPkt()
  163.  *
  164.  *  For READ and WRITE packets to/from the CON: window, print the buffer
  165.  *  to stdout.  We recognize CON: packets because ARG1 is zero (this is
  166.  *  a real kludge, but it seems to work, except we get an extra ENDCLI 
  167.  *  if you run HARDCOPY, then EMACS, then spawn a new CLI, then type ENDCLI
  168.  *  to get back to EMACS.  Can't figure that one out).
  169.  */
  170.  
  171. void PrintPkt(pkt)
  172. struct DosPacket *pkt;
  173. {
  174.    switch(pkt->dp_Type)
  175.    {
  176.       case _ACTION_READ:
  177.          if (ARG1 == 0) printBUF(ARG2,RES1);
  178.          break;
  179.  
  180.       case _ACTION_WRITE:
  181.          if (ARG1 == 0) printBUF(ARG2,RES1);
  182.          break;
  183.  
  184.       default:      /* Ignore anything else */
  185.          break;
  186.    }
  187. }
  188.  
  189.  
  190. /*
  191.  *  GetFunction()
  192.  *
  193.  *  Check the command-line arguments to see that they are valid.
  194.  *  The legal possibilities are:
  195.  *
  196.  *      TO <filename>       To begin HARDCOPY to a file
  197.  *      END                 To end the HARDCOPY session
  198.  *      MONITOR <procID>    To begin menitoring the process pointed to by
  199.  *                          <procID>.
  200.  */
  201.  
  202. GetFunction(argc,argv)
  203. int argc;
  204. char *argv[];
  205. {
  206.    int function = SHOW_USAGE;
  207.  
  208.    if (argc == 3 && stricmp(argv[1],"TO") == 0)       function = START_HARDCOPY;
  209.    else if (argc == 3 && strcmp(argv[1],"MONITOR") == 0 &&
  210.            sscanf(argv[2],"%x",&ChosenProcess) == 1)  function = DO_MONITOR;
  211.    else if (argc == 2 && stricmp(argv[1],"END") == 0) function = END_HARDCOPY;
  212.    return(function);
  213. }
  214.  
  215.  
  216. /*
  217.  *  SetupSignal()
  218.  *
  219.  *  Allocate a signal to use for our inter-task communication, and
  220.  *  set up the mask for using it.
  221.  */
  222.  
  223. void SetupSignal(theSignal)
  224. LONG *theSignal;
  225. {
  226.    *theSignal = AllocSignal(-ONE);
  227.    if (*theSignal == -ONE)
  228.    {
  229.       printf("Can't Allocate a Task Signal.\n");
  230.       exit(10);
  231.    }
  232.    WaitMask = (ONE << (*theSignal));
  233. }
  234.  
  235.  
  236. /*
  237.  *  SetupProcess()
  238.  *
  239.  *  Copy the process' name, and get its Message port.  Set our priority
  240.  *  higher than the monitored process so we will be able to react to its
  241.  *  signals, then set the pr_PktWait field to our PacketWiat() routine so
  242.  *  that we will be signalled when it receives a packet (save the old 
  243.  *  pr_PktWait so we can put it back when we're through).  Set the tc_UserData
  244.  *  field of the monitored processes Task structure to point to us, so that
  245.  *  the monitored process can signal us when it wants us to stop hardcopying.
  246.  *  Finally, send a signal to the monitored process to show that we are ready
  247.  *  to monitor it.
  248.  */
  249.  
  250. void SetupProcess(theProcess,name)
  251. struct Process *theProcess;
  252. char *name;
  253. {
  254.    strcpy(name,theProcess->pr_Task.tc_Node.ln_Name);
  255.    thePort = &theProcess->pr_MsgPort;
  256.  
  257.    Forbid();
  258.    SetTaskPri(myProcess,(ULONG)(theProcess->pr_Task.tc_Node.ln_Pri + 1)); 
  259.    OldPktWait = theProcess->pr_PktWait;
  260.    theProcess->pr_PktWait = (APTR) PWait;
  261.    OldUserData = PTR(Task,theProcess)->tc_UserData;
  262.    PTR(Task,theProcess)->tc_UserData = (APTR) myProcess;
  263.    Permit();
  264.    Signal(theProcess,SIGBREAKF_CTRL_C);
  265. }
  266.  
  267.  
  268. /*
  269.  *  MonitorProcess()
  270.  *
  271.  *  Wait for the monitored process to receive a message (our PacketWait()
  272.  *  function signals us via theSignal when it has received a message), then
  273.  *  print out the contents of the message.  A semaphore is used to coordinate
  274.  *  this routine with the PacketWait() routine (which is run asynchonously
  275.  *  by the monitored process).  Phillip Lindsay says "there are probably a
  276.  *  hundred better was of doing this.  I just went with the first one [that]
  277.  *  came to mind."  I couldn't think of a better one, so I still use it.
  278.  *  Since our process is running at a higher priority than the monitored one,
  279.  *  we should obtain the semaphore first.  The other process will block until
  280.  *  we release it (when we are done printing the contents).
  281.  */
  282.  
  283. void MonitorProcess(name,theSignal)
  284. char *name;
  285. ULONG theSignal;
  286. {
  287.    ULONG signals;
  288.    struct DosPacket *thePacket;
  289.  
  290.    do 
  291.    {
  292.       signals = Wait(SIGBREAKF_CTRL_C | WaitMask); 
  293.       ObtainSemaphore(&CanReturn); 
  294.       if (signals & WaitMask)
  295.       {
  296.          /*
  297.           *  PacketWait() signalled us so print the message it put in
  298.           *  theMessage.
  299.           */
  300.          thePacket = PTR(DosPacket,theMessage->mn_Node.ln_Name);
  301.          PrintPkt(thePacket);
  302.       }
  303.       ReleaseSemaphore(&CanReturn);
  304.    } while(!(signals & SIGBREAKF_CTRL_C)); 
  305. }
  306.  
  307.  
  308. /*
  309.  *  ClenUpProcess()
  310.  *
  311.  *  Put everything back the way we found it, except that the monitored process
  312.  *  is still running our code...
  313.  */
  314.  
  315. void CleanUpProcess(theProcess)
  316. struct Process *theProcess;
  317. {
  318.    Forbid();
  319.    theProcess->pr_PktWait = OldPktWait;
  320.    PTR(Task,theProcess)->tc_UserData = OldUserData;
  321.    Permit();
  322.    SetTaskPri(myProcess,0L);
  323. }
  324.  
  325.  
  326. /*
  327.  *  DoMonitor()
  328.  *
  329.  *  Get a signal for our PacketWait code to use to signal us when a packet is
  330.  *  ready for us to look at.  Get a semaphore so that we can make the 
  331.  *  PacketWait() routine wait for us to finish with the packet before it
  332.  *  returns the message to the monitored process.  Set up the process so 
  333.  *  that it includes our PacketWait() code.
  334.  *
  335.  *  Monitor the packet traffic, and print the I/O to the monitored CLI.
  336.  *  We wait for a signal from the PacketWait() routine, or for a 
  337.  *  CTRL-C.
  338.  *
  339.  *  When we get a CTRL-C, we are done monitoring, so we remove our
  340.  *  PacketWait() code, but the monitored process may still be in our 
  341.  *  waiting code, so we wait for a CTRL-E to verify that we are free to
  342.  *  die (and remove the PacketWait code from memory).
  343.  */
  344.  
  345. void DoMonitor()
  346. {
  347.    LONG TaskSignal;
  348.    UBYTE ProcessName[81];
  349.    
  350.    myProcess = FindTask(NULL);
  351.    if (ChosenProcess != NULL)
  352.    {
  353.       #ifndef MANX
  354.          onbreak(&Ctrl_C);    /* Turn off CTRL-C for Lattice:  we do our own */
  355.       #endif
  356.  
  357.       SetupSignal(&TaskSignal);
  358.       InitSemaphore(&CanReturn);
  359.       SetupProcess(ChosenProcess,ProcessName);
  360.    
  361.       MonitorProcess(ProcessName,TaskSignal);
  362.       
  363.       CleanUpProcess(ChosenProcess);
  364.       Wait(SIGBREAKF_CTRL_E);
  365.       FreeSignal(TaskSignal);
  366.    }
  367. }
  368.  
  369.  
  370. /*
  371.  *  StartHardCopy()
  372.  *
  373.  *  Creates the process that monitors the current process via a call to
  374.  *  Execute().  We execute a RUN command that runs HARDCOPY MONITOR and
  375.  *  passes a pointer to the current process as a parameter.  When HARDCOPY
  376.  *  starts as the remote process, it looks up this parameter and monitors
  377.  *  that process.  The output for HARDCOPY is re-directed to the file
  378.  *  that the user specified in the initial call to HARDCOPY.
  379.  *
  380.  *  The spawned process will signal us with a CTRL-C when it is set up, 
  381.  *  so wait for that signal.  Finally, print out a message; this will
  382.  *  appear as the first thing in the output file.
  383.  */
  384.  
  385. void StartHardCopy(file)
  386. char *file;
  387. {
  388.    char cmd[200],time[19];
  389.    #define COMMAND "RUN <NIL: >NIL: HARDCOPY <NIL: >\"%s\" MONITOR 0x%X"
  390.  
  391.    sprintf(cmd,COMMAND,file,FindTask(NULL));
  392.    if (!Execute(cmd,NULL,NULL))
  393.    {
  394.       printf("Can't create HARDCOPY process\n");
  395.     } else {
  396.       #ifndef MANX
  397.          onbreak(&Ctrl_C);  /* Turn off CTRL-C for Lattice:  we do our own */
  398.       #endif
  399.       printf("Waiting for HARDCOPY monitor to start ...\n");
  400.       printf("[Press CTRL-E if any errors are reported]\n");
  401.       if (Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_E) == SIGBREAKF_CTRL_E)
  402.       {
  403.          printf("\nUser signalled abort!\n\n");
  404.          printf("To remove an unwanted HARDCOPY monitor process, first try\n");
  405.          printf("giving the command HARDCOPY END.  If that doesn't work,\n");
  406.          printf("use STATUS to identify the process, and then use the BREAK\n");
  407.          printf("command to send a CTRL-C and then a CTRL-E to the HARDCOPY\n");
  408.          printf("monitor process.\n\n");
  409.       } else {
  410.          GetDateTime(time);
  411.          printf("\nHARDCOPY v1.0 recorded on %s to file \"%s\"\n",
  412.             time,file);
  413.          printf("To end the HARDCOPY session and close the file, ");
  414.          printf("type HARDCOPY END\n\n");
  415.       }
  416.    }
  417. }
  418.  
  419.  
  420. /*
  421.  *  EndHardCopy()
  422.  *
  423.  *  Sends a CTRL-C and a CTRL-E to the monitoring HARDCOPY process, which 
  424.  *  tell it to de-install the PacketWait() routine, and then die.  The
  425.  *  monitoring process has stored its address in the UserData field of
  426.  *  our process' Task structure, so we know were to send the signals.
  427.  */
  428.  
  429. void EndHardCopy()
  430. {
  431.    struct Process *MonitoringProcess;
  432.  
  433.    myProcess = FindTask(NULL);
  434.    MonitoringProcess = PTR(Process,PTR(Task,myProcess)->tc_UserData);
  435.    if (MonitoringProcess == NULL)
  436.    {
  437.       printf("No HARDCOPY process in progress\n");
  438.    } else {
  439.       Signal(MonitoringProcess,SIGBREAKF_CTRL_C);
  440.       printf("HARDCOPY output complete.\n");
  441.       Signal(MonitoringProcess,SIGBREAKF_CTRL_E);
  442.    }
  443. }
  444.  
  445. void main(argc,argv)
  446. int argc;
  447. char *argv[];
  448. {
  449.    ChosenProcess = NULL;
  450.    switch(GetFunction(argc,argv))
  451.    {
  452.       case SHOW_USAGE:
  453.          printf("Usage:  HARDCOPY TO <file>\n");
  454.          printf("   or:  HARDCOPY END\n");
  455.          break;
  456.  
  457.       case START_HARDCOPY:
  458.          StartHardCopy(argv[2]);
  459.          break;
  460.  
  461.       case DO_MONITOR:
  462.          DoMonitor();
  463.          break;
  464.  
  465.       case END_HARDCOPY:
  466.          EndHardCopy();
  467.          break;
  468.    }
  469. }
  470.  
  471.  
  472. /*
  473.  *  GetStrTime(time,date)
  474.  *
  475.  *  translates the DateStamp stored in "date" into a character string and 
  476.  *  copies it into the character string pointed to by "time", which should be 
  477.  *  at least 19 characters long.  GetStrTime properly accounts for leap years
  478.  *  every four years.  Every four centuries, however, a leap day is supposed
  479.  *  to be skipped.  AmigaDOS does not correctly interpret these non-leap
  480.  *  centuries, hence neither does GetStrTime.  In the event that AmigaDOS is 
  481.  *  ever corrected to fix this bug, you can remove the comment delimiters from
  482.  *  the line in GetStrTime that implements non-leap centuries.  Unfortunately,
  483.  *  the year 2000 is a non-leap century, hence this bug may actually
  484.  *  come into play (if anyone still has Amigas in 14 years).
  485.  */
  486.  
  487. static int
  488.    DaysIn[] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366};
  489.  
  490. static char
  491.    *NameOf[] = {"", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  492.                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  493.  
  494. #define CENTURY             (100 YEARS + 25 LEAPDAYS)
  495. #define FOURCENTURIES       (400 YEARS + 99 LEAPDAYS)
  496. #define FOURYEARS           (4 YEARS + 1 LEAPDAY)
  497. #define LEAPYEAR            (1 YEARS + 1 LEAPDAY)
  498. #define LEAPDAYS
  499. #define LEAPDAY
  500. #define YEARS               * 365
  501. #define YEAR                365
  502. #define FEBDAYS             59          /* days until the end of February */
  503.  
  504. void GetStrTime(time,date)
  505. char time[19];             /* storage area for the return value */
  506. struct DateStamp *date;    /* the DateStamp to convert */
  507. {
  508.    int year,month,day,hour,minute,second;
  509.  
  510.    day = date->ds_Days + 78 YEARS + 20 LEAPDAYS;
  511. /* day += (day - FEBDAYS - CENTURY + FOURCENTURIES) / FOURCENTURIES; */
  512.    year = 4 * (day/FOURYEARS) + 1900;
  513.    day %= FOURYEARS;
  514.    day += (day - FEBDAYS - 1 LEAPDAY) / YEAR;
  515.    year += day / LEAPYEAR;
  516.    day %= LEAPYEAR;
  517.  
  518.    for (month=1; day >= DaysIn[month]; month++);
  519.    day = day - DaysIn[month-1] + 1;
  520.  
  521.    hour   = date->ds_Minute / 60;
  522.    minute = date->ds_Minute - hour*60;
  523.    second = date->ds_Tick / TICKS_PER_SECOND;
  524.  
  525.    sprintf(time,"%02d-%3s-%02d %02d:%02d:%02d",
  526.       day,NameOf[month],(year % 100),hour,minute,second);
  527. }
  528.  
  529.  
  530. /*
  531.  *  GetDateTime(str)
  532.  *
  533.  *  Uses GetStrTime() to get the current date and time as a string.
  534.  *  "str" must be at least 19 characters long.  See GetStrTime for
  535.  *  more information.
  536.  */
  537.  
  538. void GetDateTime(str)
  539. char *str;
  540. {
  541.    struct DateStamp date;
  542.  
  543.    DateStamp(&date);
  544.    GetStrTime(str,&date);
  545. }
  546.  
  547.  
  548. /*
  549.  *  This code stub has been known to save lives... 
  550.  */
  551.  
  552. #if MANX        
  553. #asm
  554.         XREF _PacketWait
  555.  
  556.         XDEF _PWait
  557. _PWait:
  558.         movem.l a2/a3/a4,-(sp)
  559.         jsr _PacketWait
  560.         movem.l (sp)+,a2/a3/a4
  561.         rts
  562. #endasm
  563. #endif
  564.